"""
异步股票分析调度器
使用队列和多线程处理股票分析，避免阻塞API请求
"""
import logging
import threading
import queue
import time
from datetime import datetime, date
from typing import List, Dict, Optional
from concurrent.futures import ThreadPoolExecutor, as_completed

from database import SessionLocal, TradingSignal as DBTradingSignal
from api.stock_api import StockAPIClient
from analysis.signal_generator import SignalGenerator
from config import config

logger = logging.getLogger(__name__)

class AsyncStockAnalyzer:
    """异步股票分析器"""
    
    def __init__(self, max_workers: int = 5):
        self.max_workers = max_workers
        self.stock_queue = queue.Queue()
        self.result_queue = queue.Queue()
        self.is_running = False
        self.workers = []
        self.stock_api = StockAPIClient()
        self.signal_generator = SignalGenerator()
        
    def start(self):
        """启动异步分析器"""
        if self.is_running:
            logger.warning("⚠️ 异步分析器已在运行")
            return
            
        self.is_running = True
        logger.info(f"🚀 启动异步股票分析器 (工作线程: {self.max_workers})")
        
        # 启动工作线程
        for i in range(self.max_workers):
            worker = threading.Thread(
                target=self._worker_thread,
                name=f"StockAnalyzer-{i+1}",
                daemon=True
            )
            worker.start()
            self.workers.append(worker)
            
        # 启动结果处理线程
        result_handler = threading.Thread(
            target=self._result_handler,
            name="ResultHandler",
            daemon=True
        )
        result_handler.start()
        
        logger.info(f"✅ 异步分析器启动完成，{len(self.workers)}个工作线程就绪")
    
    def stop(self):
        """停止异步分析器"""
        self.is_running = False
        logger.info("🛑 正在停止异步分析器...")
        
        # 清空队列
        while not self.stock_queue.empty():
            try:
                self.stock_queue.get_nowait()
            except queue.Empty:
                break
                
        logger.info("✅ 异步分析器已停止")
    
    def add_stocks_to_queue(self, symbols: List[str]):
        """将股票添加到分析队列"""
        added_count = 0
        for symbol in symbols:
            try:
                self.stock_queue.put(symbol, block=False)
                added_count += 1
            except queue.Full:
                logger.warning(f"⚠️ 队列已满，跳过股票 {symbol}")
                
        logger.info(f"📊 已添加 {added_count} 只股票到分析队列")
        return added_count
    
    def get_queue_status(self) -> Dict:
        """获取队列状态"""
        return {
            "pending_stocks": self.stock_queue.qsize(),
            "pending_results": self.result_queue.qsize(),
            "is_running": self.is_running,
            "active_workers": len([w for w in self.workers if w.is_alive()])
        }
    
    def _worker_thread(self):
        """工作线程 - 处理股票分析"""
        thread_name = threading.current_thread().name
        logger.info(f"🔧 {thread_name} 工作线程启动")
        
        while self.is_running:
            try:
                # 从队列获取股票代码
                symbol = self.stock_queue.get(timeout=1.0)
                
                logger.debug(f"📈 {thread_name} 开始分析 {symbol}")
                start_time = time.time()
                
                # 执行股票分析
                result = self._analyze_stock(symbol)
                
                # 将结果放入结果队列
                self.result_queue.put({
                    'symbol': symbol,
                    'result': result,
                    'worker': thread_name,
                    'processing_time': time.time() - start_time
                })
                
                # 标记任务完成
                self.stock_queue.task_done()
                
                logger.debug(f"✅ {thread_name} 完成分析 {symbol} ({time.time() - start_time:.1f}秒)")
                
            except queue.Empty:
                # 队列为空，继续等待
                continue
            except Exception as e:
                logger.error(f"❌ {thread_name} 分析股票失败: {e}")
                self.stock_queue.task_done()
                
        logger.info(f"🔧 {thread_name} 工作线程结束")
    
    def _result_handler(self):
        """结果处理线程 - 保存分析结果到数据库"""
        logger.info("💾 结果处理线程启动")
        
        while self.is_running:
            try:
                # 从结果队列获取结果
                result_data = self.result_queue.get(timeout=1.0)
                
                symbol = result_data['symbol']
                result = result_data['result']
                worker = result_data['worker']
                processing_time = result_data['processing_time']
                
                if result:
                    # 保存到数据库
                    self._save_signal_to_db(symbol, result)
                    logger.info(f"💾 {symbol} 分析结果已保存 (by {worker}, {processing_time:.1f}s)")
                else:
                    logger.warning(f"⚠️ {symbol} 分析失败，无结果保存")
                
            except queue.Empty:
                # 结果队列为空，继续等待
                continue
            except Exception as e:
                logger.error(f"❌ 保存分析结果失败: {e}")
                
        logger.info("💾 结果处理线程结束")
    
    def _analyze_stock(self, symbol: str) -> Optional[Dict]:
        """分析单只股票"""
        try:
            # 1. 获取历史数据
            history = self.stock_api.get_history_data(symbol, 90)
            
            if not history or len(history) < 30:
                logger.warning(f"⚠️ {symbol} 数据不足，无法分析")
                return None
            
            # 2. 生成交易信号
            signal = self.signal_generator.generate_signal(symbol, history)
            
            if not signal:
                logger.warning(f"⚠️ {symbol} 无法生成信号")
                return None
                
            return signal
            
        except Exception as e:
            logger.error(f"❌ 分析股票 {symbol} 失败: {e}")
            return None
    
    def _save_signal_to_db(self, symbol: str, signal: Dict):
        """保存信号到数据库"""
        db = SessionLocal()
        
        try:
            today = date.today()
            
            # 检查今天是否已有信号
            existing = db.query(DBTradingSignal).filter(
                DBTradingSignal.symbol == symbol,
                DBTradingSignal.signal_date == today
            ).first()
            
            if existing:
                # 更新现有信号
                existing.signal_type = signal['signal_type']
                existing.price = signal['price']
                existing.strength = signal['strength']
                existing.reason = signal['reason']
                existing.action_price = signal.get('action_price')
                existing.target_price = signal.get('target_price')
                existing.stop_loss = signal.get('stop_loss')
                logger.debug(f"🔄 {symbol} 信号已更新")
            else:
                # 创建新信号
                db_signal = DBTradingSignal(
                    symbol=symbol,
                    signal_type=signal['signal_type'],
                    price=signal['price'],
                    strength=signal['strength'],
                    reason=signal['reason'],
                    action_price=signal.get('action_price'),
                    target_price=signal.get('target_price'),
                    stop_loss=signal.get('stop_loss'),
                    signal_date=today
                )
                db.add(db_signal)
                logger.debug(f"✅ {symbol} 新信号已保存")
            
            db.commit()
            
        except Exception as e:
            logger.error(f"❌ 保存 {symbol} 信号到数据库失败: {e}")
            db.rollback()
        finally:
            db.close()


class AsyncStockScheduler:
    """异步股票调度器"""
    
    def __init__(self):
        self.analyzer = AsyncStockAnalyzer(max_workers=3)  # 3个工作线程
        self.is_running = False
        self.scheduler_thread = None
        
    def start(self):
        """启动异步调度器"""
        if self.is_running:
            logger.warning("⚠️ 异步调度器已在运行")
            return
            
        self.is_running = True
        
        # 启动分析器
        self.analyzer.start()
        
        # 启动调度线程
        self.scheduler_thread = threading.Thread(
            target=self._scheduler_loop,
            name="AsyncScheduler",
            daemon=True
        )
        self.scheduler_thread.start()
        
        logger.info("🚀 异步股票调度器启动完成")
        logger.info("⏰ 调度计划: 交易时间段每1小时更新一次")
        logger.info("📊 处理模式: 异步队列 + 多线程并发")
        
    def stop(self):
        """停止异步调度器"""
        self.is_running = False
        if self.analyzer:
            self.analyzer.stop()
        logger.info("🛑 异步股票调度器已停止")
    
    def trigger_analysis(self):
        """手动触发分析"""
        if not self.is_running:
            logger.warning("⚠️ 调度器未运行，无法触发分析")
            return False
            
        symbols = [f"sh{s}" if s.startswith("6") else f"sz{s}" for s in config.POPULAR_STOCKS]
        added_count = self.analyzer.add_stocks_to_queue(symbols)
        
        logger.info(f"🎯 手动触发分析: 已添加 {added_count} 只股票到队列")
        return True
    
    def get_status(self) -> Dict:
        """获取调度器状态"""
        if not self.analyzer:
            return {"status": "stopped"}
            
        queue_status = self.analyzer.get_queue_status()
        return {
            "status": "running" if self.is_running else "stopped",
            "scheduler_alive": self.scheduler_thread.is_alive() if self.scheduler_thread else False,
            **queue_status
        }
    
    def _scheduler_loop(self):
        """调度循环"""
        logger.info("⏰ 异步调度循环启动")
        last_run_time = datetime.now()
        
        # 启动时立即执行一次
        self.trigger_analysis()
        
        while self.is_running:
            try:
                now = datetime.now()
                
                # 检查是否是交易时间
                if self._is_trading_time():
                    # 计算距离上次运行的时间差
                    time_diff = (now - last_run_time).total_seconds()
                    
                    # 如果距离上次运行超过1小时（3600秒），则执行任务
                    if time_diff >= 3600:
                        logger.info(f"⏰ 触发定时分析（距上次运行 {int(time_diff/60)} 分钟）")
                        self.trigger_analysis()
                        last_run_time = now
                    else:
                        # 等待到下一个1小时间隔
                        remaining = 3600 - time_diff
                        logger.debug(f"⏳ 交易时间内，下次更新还需 {int(remaining/60)} 分钟")
                else:
                    # 非交易时间，等待到下一个交易时段
                    logger.debug(f"💤 非交易时间，等待中... (当前时间: {now.strftime('%H:%M:%S')})")
                
                # 每分钟检查一次
                time.sleep(60)
                
            except Exception as e:
                logger.error(f"❌ 调度循环异常: {e}")
                time.sleep(60)
                
        logger.info("⏰ 异步调度循环结束")
    
    def _is_trading_time(self) -> bool:
        """判断当前是否是交易时间"""
        now = datetime.now()
        current_time = now.time()
        current_weekday = now.weekday()
        
        # 周末不交易（周六=5, 周日=6）
        if current_weekday >= 5:
            return False
        
        # 交易时间段：
        # 上午：9:30-11:30
        # 下午：13:00-15:00
        from datetime import time as dt_time
        
        morning_start = dt_time(9, 30)
        morning_end = dt_time(11, 30)
        afternoon_start = dt_time(13, 0)
        afternoon_end = dt_time(15, 0)
        
        is_morning = morning_start <= current_time <= morning_end
        is_afternoon = afternoon_start <= current_time <= afternoon_end
        
        return is_morning or is_afternoon


# 全局异步调度器实例
async_scheduler = AsyncStockScheduler()
